package Models

import (
	"encoding/json"
	"fmt"
	opb "gPublic/grpc/yz-pub-data/openData"
	"reflect"
)

type IsEnable int8

const (
	IsEnableShow IsEnable = 1
	IsEnableHide IsEnable = 0
)

type GZWebMenus struct {
	Id             int64    `json:"id" gorm:"primary_key"`
	Title          string   `json:"title" gorm:"size:255"`
	ParentId       int64    `json:"parent_id" gorm:"type:int;size:4"`
	MenuType       string   `json:"menu_type"`
	Content        string   `json:"content" gorm:"type:text"`
	Orderby        int64    `json:"orderby"`
	IsEnable       IsEnable `json:"is_enable"`
	SeoDescription string   `json:"seo_description" gorm:"size:255"`
	Seoeywords     string   `json:"seo_keywords" gorm:"size:255"`
	Closed         int64    `json:"closed"`
	CreatedAt      int64    `json:"create_time"`
	UpdatedAt      int64    `json:"update_time"`
}

// TreeNodeExtractor 定义了从结构体中提取节点信息的接口
type TreeNodeExtractor interface {
	GetID() int64
	GetParentID() int64
}

func (m *GZWebMenus) GetID() int64 {
	return m.Id
}

func (m *GZWebMenus) GetParentID() int64 {
	return m.ParentId
}

type MenusCondition struct {
	Closed   int
	IsEnable int8
}

func BJ() {
	var a Menus
	var b Menus

	// 在这个例子中，StructA 和 StructB 虽然不同，但它们的字段是一致的。reflect.DeepEqual 函数会进行深度比较，确保两个结构体的字段以及它们的值都是一致的。如果结构体中包含了切片、映射或者其他引用类型的字段，这种方法同样适用
	// 深度对比 字段 和值
	if reflect.DeepEqual(a, b) {
		fmt.Println("Structures are identical.")
	} else {
		fmt.Println("Structures are not identical.")
	}
}

func GetALLMenus() ([]GZWebMenus, error) {
	cfg := []GZWebMenus{}
	err := DB.Where(MenusCondition{Closed: 0, IsEnable: 1}).Order("orderby desc").Find(&cfg).Error // 0 默认不显示哎sql中
	return cfg, err
}

type FuncPage struct {
	Link string
}

func BuildMenuTree(menus []*GZWebMenus) []*opb.MenuItem {
	childrenData := []GZWebMenus{}
	var data []*opb.MenuItem
	var menuItem opb.MenuItem
	var ct opb.Content

	funcPage := FuncPage{}

	for _, menu := range menus {
		var jcdata map[string]string
		errjc := json.Unmarshal([]byte(menu.Content), &jcdata)
		if errjc != nil {
			fmt.Println("解析JSON失败:", err)
		}

		if jc, ok := jcdata["link"]; ok {
			ct.Link = jc           // 赋值出来
			menuItem.Content = &ct // 内容
		}

		if menu.MenuType == "function_page" {
			err := DB.Table("gz_function_page").Where("id = ?", menu.Id).Find(&funcPage).Error
			if err != nil {
				fmt.Println("查询失败！:", errjc)
			}
			ct.Link = funcPage.Link
			menuItem.Content = &ct // 如果有值 则覆盖内容
		}
		menuItem.Id = menu.Id
		menuItem.ParentId = int32(menu.ParentId)
		menuItem.Title = menu.Title
		menuItem.MenuType = menu.MenuType
		menuItem.SeoDescription = menu.SeoDescription
		menuItem.SeoKeywords = menu.Seoeywords

		cerr := DB.Where("is_enable = ? and closed = ? and parent_id = ?", 1, 0, menu.ParentId).Find(&childrenData).Error
		if cerr != nil {
			fmt.Println("查询失败！:", err)
		}

		for _, v := range childrenData {
			errjc := json.Unmarshal([]byte(v.Content), &jcdata)
			if errjc != nil {
				fmt.Println("解析JSON失败:", errjc)
			}

			if jc, ok := jcdata["link"]; ok {
				ct.Link = jc           // 赋值出来
				menuItem.Content = &ct // 内容
			}

			if menu.MenuType == "function_page" {
				err := DB.Table("gz_function_page").Where("id = ?", v.Id).Find(&funcPage).Error
				if err != nil {
					fmt.Println("查询失败！:", err)
				}
				ct.Link = funcPage.Link
				menuItem.Content = &ct // 如果有值 则覆盖内容
			}

			data = append(data, &menuItem)
		}
		menuItem.Children = data
	}
	fmt.Print("-----------------")
	return data
}

// -------------------------------------------- 以下 为测试用 --------------------------------------------
type Content struct {
	Link string
}

type GZWebMenusTee struct {
	Id             int64
	Title          string
	ParentId       int32
	MenuType       string
	Content        Content
	SeoDescription string
	SeoKeywords    string
	Children       []*GZWebMenusTee
}

type Menus struct {
	WebMenus []*GZWebMenusTee
}

func (GZWebMenus) TableName() string {
	return "gz_web_menu"
}

// 树形结构
func GetMenuTree(menus []*GZWebMenus) []*opb.MenuItem {
	var data []*opb.MenuItem
	for _, menu := range menus {
		// ct := Content{
		// 	Link: "测试",
		// }
		// root := GZWebMenusTee{
		// 	Id:             menu.Id,
		// 	Title:          menu.Title,
		// 	ParentId:       int32(menu.ParentId),
		// 	MenuType:       menu.MenuType,
		// 	Content:        ct,
		// 	SeoDescription: menu.SeoDescription,
		// 	SeoKeywords:    menu.Seoeywords,
		// }

		if menu.ParentId == 0 {
			rr := GetChildren(menus, menu)
			data = append(data, rr)
		}
		// data = append(data, &root)	// 防止独立的数据
	}
	return data
}

func GetChildren(menus []*GZWebMenus, menu *GZWebMenus) *opb.MenuItem {
	var c []*opb.MenuItem
	ctree := opb.MenuItem{
		Id:             menu.Id,
		Title:          menu.Title,
		ParentId:       int32(menu.ParentId),
		MenuType:       menu.MenuType,
		Content:        &opb.Content{Link: "测试link"},
		SeoDescription: menu.SeoDescription,
		SeoKeywords:    menu.Seoeywords,
	}

	for _, child := range menus {
		if int32(menu.Id) == int32(child.ParentId) {
			subTree := GetChildren(menus, child)
			c = append(c, subTree)
		}
	}
	ctree.Children = c
	// fmt.Printf("ctree: %#v\n", ctree)
	return &ctree
}

// 方法二 更合适
func GetMenuTree2(menus []*GZWebMenus) []*opb.MenuItem {
	menusMap := make(map[int64]*opb.MenuItem)
	var root []*opb.MenuItem

	for _, menu := range menus {
		gzMenu := opb.MenuItem{
			Id:             menu.Id,
			Title:          menu.Title,
			ParentId:       int32(menu.ParentId),
			MenuType:       menu.MenuType,
			Content:        &opb.Content{Link: "测试"},
			SeoDescription: menu.SeoDescription,
			SeoKeywords:    menu.Seoeywords,
		}

		// 存储节点到 map 中
		menusMap[menu.Id] = &gzMenu

		// 如果是顶层节点，则加入到根节点数组中
		if menu.ParentId == 0 {
			root = append(root, &gzMenu)
		}
	}

	// 非  主节点
	for _, menu := range menus {
		if menu.ParentId != 0 {
			parent := menusMap[menu.ParentId]
			child := menusMap[menu.Id]
			parent.Children = append(parent.Children, child)
		}
	}

	return root
}
